package spring.cloud.service.task.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import spring.cloud.service.task.domain.executor.ExecutorInfo;
import spring.cloud.service.task.domain.task_executor.TaskExecutorStatus;
import spring.cloud.service.task.service.ExecutorService;
import spring.cloud.service.task.utils.Result;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@RequestMapping("/nameSpaces/executors")
public class ExecutorController {
    private static final String TRAFFIC_OPERATION_EXTRACT = "extract";
    private static final String TRAFFIC_OPERATION_RECOVER = "recover";
    @Resource
    private ExecutorService executorService;
    /*
     * 摘流量与流量恢复
     */

    /**
     * 一键重排
     */

    @RequestMapping(value = "/shardAll")
    public Result shardAll(final HttpServletRequest request, @PathVariable String nameSpace) throws RuntimeException {
        executorService.shardAll(nameSpace);
        return new Result();
    }

    /*
     * 批量摘流量与流量恢复
     */

    /**
     * 一键重启。
     */
    @RequestMapping(value = "/executor/restart")
    public Result restart(final HttpServletRequest request,
                          @PathVariable String nameSpace,
                          @PathVariable String executorId) {
        checkExecutorStatus(nameSpace, executorId, TaskExecutorStatus.ONLINE, "Executor必须在线才可以重启");
        executorService.restart(nameSpace, executorId);
        return new Result();
    }

    @RequestMapping(value = "/executor/extractOrRecoverTraffic")
    public Result extractOrRecoverTraffic(final HttpServletRequest request,
                                          @PathVariable String nameSpace,
                                          @PathVariable String executorId,
                                          @RequestParam String operation) throws RuntimeException {

        extractOrRecoverTraffic(nameSpace, executorId, operation);
        return new Result();
    }

    @RequestMapping(value = "/batchExtractOrRecoverTraffic")
    public Result batchExtractOrRecoverTraffic(final HttpServletRequest request,
                                               @PathVariable String nameSpace,
                                               @RequestParam List<String> executorIdList,
                                               @RequestParam String operation) throws RuntimeException {

        List<String> success2ExtractOrRecoverTrafficExecutors = new ArrayList<String>();
        List<String> fail2ExtractOrRecoverTrafficExecutors = new ArrayList<String>();
        for (String executorId : executorIdList) {
            try {
                extractOrRecoverTraffic(nameSpace, executorId, operation);
                success2ExtractOrRecoverTrafficExecutors.add(executorId);
            } catch (Exception e) {
                log.warn("exception happens during extract or recover traffic of executor:" + executorId, e);
                fail2ExtractOrRecoverTrafficExecutors.add(executorId);
            }
        }

        if (!fail2ExtractOrRecoverTrafficExecutors.isEmpty()) {
            StringBuilder message = new StringBuilder();
            message.append("操作成功的executor:").append(success2ExtractOrRecoverTrafficExecutors).append("，")
                    .append("操作失败的executor:").append(fail2ExtractOrRecoverTrafficExecutors);
            throw new RuntimeException(message.toString());
        }

        return new Result();
    }

    private void extractOrRecoverTraffic(String nameSpace, String executorId, String operation) {
        if (TRAFFIC_OPERATION_EXTRACT.equals(operation)) {
            executorService.extractTraffic(nameSpace, executorId);
        } else if (TRAFFIC_OPERATION_RECOVER.equals(operation)) {
            executorService.recoverTraffic(nameSpace, executorId);
        } else {
            throw new IllegalArgumentException("operation " + operation + "不支持");
        }
    }

    /**
     * 移除executor
     */
    @RequestMapping(value = "/executor/removeExecutor")
    public Result removeExecutor(final HttpServletRequest request,
                                 @PathVariable String nameSpace,
                                 @PathVariable String executorId) throws RuntimeException {

        checkExecutorStatus(nameSpace, executorId, TaskExecutorStatus.OFFLINE, "Executor在线，不能移除");
        executorService.removeExecutor(nameSpace, executorId);
        return new Result();
    }

    /**
     * 批量移除executor
     */

    @RequestMapping(value = "/batchRemoveExecutors")
    public Result batchRemoveExecutors(final HttpServletRequest request,
                                       @PathVariable String nameSpace,
                                       @RequestParam List<String> executorIdList) throws RuntimeException {
        //assertIsPermitted(PermissionKeys.executorBatchRemove, nameSpace);
        // check executor is existed and online.
        List<String> success2RemoveExecutors = new ArrayList<String>();
        List<String> fail2RemoveExecutors = new ArrayList<String>();
        for (String executorId : executorIdList) {
            try {
                checkExecutorStatus(nameSpace, executorId, TaskExecutorStatus.OFFLINE, "Executor在线，不能移除");
                executorService.removeExecutor(nameSpace, executorId);
                success2RemoveExecutors.add(executorId);
            } catch (Exception e) {
                log.warn("exception happens during remove executor:" + executorId, e);
                fail2RemoveExecutors.add(executorId);
            }
        }
        if (!fail2RemoveExecutors.isEmpty()) {
            StringBuilder message = new StringBuilder();
            message.append("删除成功的executor:").append(success2RemoveExecutors).append("，").append("删除失败的executor:").append(fail2RemoveExecutors);
            throw new RuntimeException(message.toString());
        }

        return new Result();
    }

    private void checkExecutorStatus(String nameSpace, String executorId, String taskExecutorStatus, String errMsg) throws RuntimeException {
        ExecutorInfo executorInfo = executorService.getExecutorInfo(nameSpace, executorId);
        if (executorInfo == null) {
            throw new RuntimeException("Executor不存在");
        }
        if (taskExecutorStatus != executorInfo.getStatus()) {
            throw new RuntimeException(errMsg);
        }
    }

    /**
     * 获取域下所有executor基本信息
     */
    @RequestMapping(value = "/getExecutorInfoList")
    public Result getExecutorInfoList(final HttpServletRequest request, @PathVariable String nameSpace, @RequestParam(required = false) String status) throws RuntimeException {
        if ("online".equalsIgnoreCase(status)) {
            return Result.success(executorService.getExecutorInfoList(nameSpace, TaskExecutorStatus.ONLINE));
        }
        return Result.success(executorService.getExecutorInfoList(nameSpace));
    }

    /**
     * 获取executor被分配的任务分片信息
     */

    @GetMapping(value = "/executor/getExecutorTaskItemAssignInfo")
    public Result getExecutorTaskItemAssignInfo(final HttpServletRequest request, @PathVariable String nameSpace, @PathVariable String executorId) throws RuntimeException {
        return Result.success(executorService.getExecutorTaskItemAssignInfo(nameSpace, executorId));
    }

    /**
     * 获取executor运行中的任务分片信息
     */

    @GetMapping(value = "/executor/getExecutorRunningInfo")
    public Result getExecutorRunningInfo(final HttpServletRequest request, @PathVariable String nameSpace, @PathVariable String executorId) throws RuntimeException {
        return Result.success(executorService.getExecutorRunningInfo(nameSpace, executorId));
    }

}
